package cn.fboost.mtos.configuration;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;

import javax.validation.constraints.NotNull;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        Set<String> cacheNames = new HashSet<>();
        cacheNames.add("default");
        cacheNames.add("sys-config");

        ConcurrentHashMap<String, RedisCacheConfiguration> configMap = new ConcurrentHashMap<>();
        // 常驻缓存
        configMap.put("default", config);

        // sys-config 系统配置项 有效期60分钟
        configMap.put("sys-config", config.entryTtl(Duration.ofMinutes(60)));

        //需要先初始化缓存名称，再初始化其它的配置。
        return RedisCacheManager.builder(factory).initialCacheNames(cacheNames).withInitialCacheConfigurations(configMap).build();
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return new CacheErrorHandler() {
            @Override
            public void handleCachePutError(@NotNull RuntimeException exception, @NotNull Cache cache, @NotNull Object key, Object value) {
                handleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheGetError(@NotNull RuntimeException exception, @NotNull Cache cache, @NotNull Object key) {
                handleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheEvictError(@NotNull RuntimeException exception, @NotNull Cache cache, @NotNull Object key) {
                handleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheClearError(@NotNull RuntimeException exception, @NotNull Cache cache) {
                handleRedisErrorException(exception, null);
            }
        };
    }

    protected void handleRedisErrorException(RuntimeException exception, Object key) {
        log.error(String.format("Redis Error [key=%s]: %s", key, exception.getMessage()));
    }
}
